package xuan.gui;

import java.awt.BorderLayout;

import java.awt.Dimension;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.swing.AbstractButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.JCheckBox;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import xuan.lib.*;
import org.roblybarger.*;
import name.fraser.neil.plaintext.*;
import name.fraser.neil.plaintext.diff_match_patch.Diff;

import java.awt.FlowLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.JEditorPane;
import javax.swing.JLabel;


/**
 * replays all operations according to the order set by sort algo
 * 
 * @author xuan
 *
 */
public class ReplayMergePanel extends JPanel {

	public Document getSource() {
		return source;
	}

	private JTree tree;
	private XMLTreeModel model;
	private List<JCheckBox> opList;
	public Document source;
	public Document merged;
	private EditLog el;
	private Merge merge;
	private JPanel logPanel;
	private int cpt=0;
	private JScrollPane scrollPane;
	private JEditorPane textPane;
	private JPanel panel;
	
	public ReplayMergePanel() {
		setLayout(new BorderLayout());
		
		String[] args=new String[3];
		args[0]= "/home/xuan/workspace/3DMBetaTest/base.xml";
		args[1]= "/home/xuan/workspace/3DMBetaTest/merged.xml";
		args[2]= "/home/xuan/workspace/3DMBetaTest/edit.log";
		merge = new Merge(args);
		source = merge.getSource();
		merged = merge.getMerged();		
		el = merge.geteLog();
		
		model = new XMLTreeModel();
		
		logPanel = new JPanel();
		FlowLayout flowLayout = (FlowLayout) logPanel.getLayout();
		flowLayout.setAlignment(FlowLayout.LEFT);
		logPanel.setPreferredSize(new Dimension(400, 400));
		logPanel.setLayout(new javax.swing.BoxLayout(logPanel, javax.swing.BoxLayout.Y_AXIS));
		JScrollPane scrollpane = new JScrollPane(logPanel);
		scrollpane.setPreferredSize(new Dimension(300, 400));
		add(scrollpane, BorderLayout.WEST);
		
		JLabel lblOperations = new JLabel("Operations");
		scrollpane.setColumnHeaderView(lblOperations);
		
		tree = new JTree();
		tree.setPreferredSize(new Dimension(400, 400));
		tree.setModel(model);
		tree.setShowsRootHandles(true);
		tree.setEditable(false);
		
		JScrollPane treePane = new JScrollPane(tree);
		treePane.setMinimumSize(new Dimension(300, 400));
		treePane.setPreferredSize(new Dimension(500, 400));
		add(treePane, BorderLayout.EAST);
		
		JLabel lblDocumentTree = new JLabel("Document Tree");
		treePane.setColumnHeaderView(lblDocumentTree);
		
		scrollPane = new JScrollPane();
		scrollPane.setPreferredSize(new Dimension(800, 200));
		add(scrollPane, BorderLayout.SOUTH);
		
		textPane = new JEditorPane();
		textPane.setContentType("text/html");
		textPane.setEditorKit(new HTMLEditorKit());
		textPane.setEditable(false);
		scrollPane.setViewportView(textPane);

		panel = new JPanel();
		FlowLayout flowLayout_1 = (FlowLayout) panel.getLayout();
		flowLayout_1.setAlignment(FlowLayout.LEFT);
		scrollPane.setColumnHeaderView(panel);
		
		JLabel lblTextNode = new JLabel("Text Node");
		panel.add(lblTextNode);
			
		tree.addTreeSelectionListener(new TreeSelectionListener() {
			public void valueChanged(TreeSelectionEvent e) {
				Object lpc = e.getPath().getLastPathComponent();
				if (lpc instanceof XMLTreeNode) {
					textPane.setText( ((XMLTreeNode)lpc).getText());
				}
			}
		});
		
	}
	
	public void setDocuments() {		
		model.setDocument(source);
		preview(el.getOperation(0));		
	}


	public void setEditLog() {
		List<Operation> edits = el.get();
		opList = new LinkedList<JCheckBox>();
		
		
		for(Iterator<Operation> it=edits.iterator();it.hasNext();){
			Operation op = (Operation) it.next();
			String str=op.toString();
			JCheckBox chckbxNewCheckBox = new JCheckBox(str);
			opList.add(chckbxNewCheckBox);
			logPanel.add(chckbxNewCheckBox);
			chckbxNewCheckBox.addItemListener(new CheckedItem() );
			if(!op.isEnabled()){
				chckbxNewCheckBox.setEnabled(false);
			}
		}		
	}

	private void preview(Operation op) {
		merge.previewFirstOperation();
		model.reload();
		TreeUtils.expandAll(tree);
		TreeCellCustomRenderer renderer;
		Object insert, delete, update;
		
		switch(op.getType()){
		case INSERT:
			if(op.getSourceNode().getNodeType()==Node.TEXT_NODE){
				insert = new XMLTreeNode((Element)op.getSourceNode().getParentNode());
				renderer = new TreeCellCustomRenderer(insert, null,null,true);
				tree.setCellRenderer(renderer);				
				diff_match_patch diffText = new diff_match_patch();
				textPane.setText(diffText.diff_prettyHtml(diffText.diff_main("", op.getSourceNode().getTextContent())));
			}
			else{
				insert = new XMLTreeNode((Element)op.getSourceNode());
				renderer = new TreeCellCustomRenderer(insert, null,null, false);
				tree.setCellRenderer(renderer);
			}
			break;
		case DELETE:
			if(op.getSourceNode().getNodeType()==Node.TEXT_NODE){
				delete = new XMLTreeNode((Element)op.getSourceNode().getParentNode());
				renderer = new TreeCellCustomRenderer(null, delete,null,true);
				tree.setCellRenderer(renderer);
				diff_match_patch diffText = new diff_match_patch();
				textPane.setText(diffText.diff_prettyHtml(diffText.diff_main(op.getSourceNode().getTextContent(),"")));
			}
			else{
				delete = new XMLTreeNode((Element)op.getSourceNode());
				renderer = new TreeCellCustomRenderer(null,delete,null,false);
				tree.setCellRenderer(renderer);
			}
			break;
		case UPDATE:
			if(op.getSourceNode().getNodeType()==Node.TEXT_NODE){
				update = new XMLTreeNode((Element)op.getSourceNode().getParentNode());
				renderer = new TreeCellCustomRenderer(null, null,update,true);
				tree.setCellRenderer(renderer);
				diff_match_patch diffText = new diff_match_patch();				
				LinkedList<Diff> diffs = diffText.diff_main(op.getSourceNode().getTextContent(), op.getMergedNode().getTextContent());
				diffText.diff_cleanupSemantic(diffs);
				textPane.setText(diffText.diff_prettyHtml(diffs));
			}
			else{
				update = new XMLTreeNode((Element)op.getSourceNode());
				renderer = new TreeCellCustomRenderer(null, null,update,false);
				tree.setCellRenderer(renderer);
			}
			break;
		case MOVE:
			if(op.getSourceNode().getNodeType()==Node.TEXT_NODE){
				insert = new XMLTreeNode((Element)op.getTargetNode().getParentNode());
				delete = new XMLTreeNode((Element)op.getSourceNode().getParentNode());
				renderer = new TreeCellCustomRenderer(insert,delete,null,true);
				tree.setCellRenderer(renderer);
				textPane.setText(op.getSourceNode().getTextContent());
				textPane.setForeground(null);
			}
			else{
				insert = new XMLTreeNode((Element)op.getTargetNode());
				delete = new XMLTreeNode((Element)op.getSourceNode());
				renderer = new TreeCellCustomRenderer(insert, delete,null,false);
				tree.setCellRenderer(renderer);
			}
			break;
		default:
			if(op.getSourceNode().getNodeType()==Node.TEXT_NODE){
				insert = new XMLTreeNode((Element)op.getTargetNode().getParentNode());
				update = new XMLTreeNode((Element)op.getSourceNode().getParentNode());
				renderer = new TreeCellCustomRenderer(insert,null,update,true);
				tree.setCellRenderer(renderer);
				textPane.setText(op.getSourceNode().getTextContent());
				textPane.setForeground(null);
			}
			else{
				insert = new XMLTreeNode((Element)op.getTargetNode());
				update = new XMLTreeNode((Element)op.getSourceNode());
				renderer = new TreeCellCustomRenderer(insert, null,update,false);
				tree.setCellRenderer(renderer);
			}
		}
	}

	private void updateLogPanel() {
		JCheckBox checkBox;
		int j=0;
		opList.get(cpt-1).setEnabled(false);
		for(int i=cpt; i< opList.size();i++){
			checkBox = opList.get(i);
			checkBox.setText(el.getOperation(j).toString());
			if(el.getOperation(j).isEnabled()){
				checkBox.setEnabled(true);
			}
			j++;
		}
	}

	class CheckedItem implements ItemListener{
		public void itemStateChanged(ItemEvent itemEvent) {
	        @SuppressWarnings("unused")
			AbstractButton abstractButton = (AbstractButton)itemEvent.getSource();
	        int state = itemEvent.getStateChange();
	       
	        if (state == ItemEvent.SELECTED) {			        				        	
	        	cpt++;			        	
	        	merge.executeFirstOperation();
	        	model.reload();
	        	TreeUtils.expandAll(tree);	        				        	
	        	try{
	        		updateLogPanel();
	        		preview(el.getOperation(0));
	        	}
	        	catch(Exception e){
	        		JOptionPane.showMessageDialog(panel, "Merging is competed.");
	        		
	        		try {
						DocUtils.exportXMLFile(source,"");
					} catch (Exception e1) {
						e1.printStackTrace();
					}
	        	}
	        }
		}
	}
}
